package com.xcc.mrpbmp;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.util.Log;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;

/**
 * Created by 磁磁帅 on 2021/6/4.
 * 功能：
 */
public class BmpLoad {
    public static final String[] AssetsDataName = new String[]{
            "meimei_500.bmp",
            "流氓兔_120.bmp",
            "music_bg.bmp"};
    public static final int[] W = {500, 120, 240};
    public static final int[] H = {750, 160, 320};
    private Context context;

    public BmpLoad(Context context) {
        this.context = context;
    }

    public Bitmap loadBitmap(int index) {//, H[index]
        if (BuildConfig.DEBUG) Log.i("-xcc-", "loadBitmap: ");
        return loadBitmap(AssetsDataName[index], W[index]);
    }

    /**
     * 这部分代码是我尝试进行优化，均以失败告终。<br />
     * 以meimei_500图为例，本人手机加载耗时50毫秒左右。<br />
     * 该图的原图jpg文件加载，手机耗时23毫秒左右。<br />
     * 原图加载比bmp快一倍，尝试优化代码，仍达不到原图加载速度。<br />
     * 加载图片耗时操作：读取IO、解密、createBitmap。<br />
     * createBitmap：提供color[]即可,没有优化代码空间。<br />
     * 解密：两个byte生成一个 int color，主要操作已位运算为主，可操作空间不大。<br />
     * 读取IO：此处快速读出byte[]，并转换成color[]，应该可以节省大量时间;<br />
     * 1、直接read(new byte[2])，然byte[2]转color，然而该过程频繁读取IO极其耗时;<br />
     * 2、read(new byte[1024])，不转ByteArrayOutputStream，同时byte[1024]可以解密出color[512]，并没有提高性能，却出现图片花屏(不知为何);<br />
     * 3、计算byte[]长度，只需要执行一次read(byte)，性能没有明显提高，同时出现图片黑屏。此处byte[]可能长750000，猜测过长不利于IO读取;<br />
     * 4、最终方案new ByteArrayOutputStream(750000),ByteArrayOutputStream类似于ArrayList，内部有个byte[32]。
     * 因为初始长度为32，write操作会导致反复延长数组。该操作性能提高到40毫秒，提高有限，该部分代码就没保留了。<br />
     * <p>
     * 总结：<br />
     * 1、IO操作耗时，原图jpg体积小，IO读写肯定快于bmp。<br />
     * 2、ByteArrayOutputStream.toByteArray是一个复制数组的操作，仍然得消耗性能，使用ArrayList<Byte>应该会性能更优。<br />
     * 3、jpg加载需要读取IO、解码，其解码开销应该大于bmp解密操作，那么可能是手机硬件加速试其性能更好。<br />
     * 4、mrp使用的bmp图，其mrp平台应该也存在硬件加速，如这样早期山寨机加载mrp图会性能优于jpg图。<br />
     * ------------------所以我这是在用软件追赶硬件性能？？？
     * 使用ArrayList<Byte>，实测性能未提反降
     */
    public Bitmap loadBitmap(String assetsName, int imgW, int imgH) {
        int size = imgW * imgH;
        int[] colors = new int[size];
        int index = 0;
        InputStream resourceAsStream = context.getClass().getClassLoader()
                .getResourceAsStream("assets/" + assetsName);
        try {
            //使用ArrayList<Byte>
            /*int len = size << 1;
            List<Byte> byteList = new ArrayList<>(len);
            byte[] buffer = new byte[1024];
            while ((len = resourceAsStream.read(buffer)) > 0) {
                for (int i = 0; i < len; i++) {
                    byteList.add(buffer[i]);
                }
            }
            for (int i = 0; i < size; i++) {
                int i1 = i << 1;
                byte b1 = byteList.get(i1);
                byte b2 = byteList.get(i1 + 1);
                int it = b1 & 0xFF;
                it = (it << 8) + (b2 & 0xFF);
                colors[i] = getRGB((short) it);
            }*/
            //直接读完IO
            /*//int len = resourceAsStream.available();
            int len = size << 1;
            byte[] buffer = new byte[len];//一次IO读取并没有加速
            resourceAsStream.read(buffer);//稍微大点的图出现了黑屏现象
            for (int i = 0; i < len; i += 2) {
                byte b1 = buffer[i];
                byte b2 = buffer[i + 1];
                int it = b1 & 0xFF;
                it = (it << 8) + (b2 & 0xFF);
                colors[index] = getRGB((short) it);
                index++;
            }*/
            //读取IO同时解密,这种读取速度并没有加快
            /*int len = 0;
            byte[] buffer = new byte[1024];
            while ((len = resourceAsStream.read(buffer)) > 0) {
                for (int i = 0; i < len; i += 2) {//稍微大点的图出现了花屏现象
                    byte b1 = buffer[i];
                    byte b2 = buffer[i + 1];
                    int it = b1 & 0xFF;
                    it = (it << 8) + (b2 & 0xFF);
                    colors[index] = getRGB((short) it);
                    index++;
                }
            }*/
            //双字节读取(直接故障,同时反复读取IO耗时)
            /*byte[] buffer = new byte[2];
            while (resourceAsStream.read(buffer) >= 2) {
                byte b1 = buffer[0];
                byte b2 = buffer[1];
                int it = b1 & 0xFF;
                it = (it << 8) + (b2 & 0xFF);
                colors[index] = getRGB((short) it);
                index++;
            }*/
            resourceAsStream.close();
        } catch (Exception e) {
            if (BuildConfig.DEBUG) e.printStackTrace();
        }
        return Bitmap.createBitmap(colors, imgW, imgH, Bitmap.Config.RGB_565);
    }

    public Bitmap loadBitmap(String assetsName, int imgW) {
        InputStream resourceAsStream = context.getClass().getClassLoader()
                .getResourceAsStream("assets/" + assetsName);
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();//此处给出具体长度可以提高性能
        byte[] bytes = null;
        try {
            int len = 0;
            byte[] buffer = new byte[1024];
            while ((len = resourceAsStream.read(buffer)) > 0) {
                outputStream.write(buffer, 0, len);
            }
            bytes = outputStream.toByteArray();

            outputStream.close();
            resourceAsStream.close();
        } catch (Exception e) {
            if (BuildConfig.DEBUG) e.printStackTrace();
        }
        if (bytes == null) return null;
        int length = bytes.length;
        int size = length >>> 1;//像素点数量
        int[] colors = new int[size];
        for (int i = 0; i < size; i++) {
            int i1 = i << 1;
            byte b1 = bytes[i1];
            byte b2 = bytes[i1 + 1];
            int it = b1 & 0xFF;
            it = (it << 8) + (b2 & 0xFF);
            colors[i] = getRGB((short) it);
        }
        int H = size / imgW;//图片高度
        return Bitmap.createBitmap(colors, imgW, H, Bitmap.Config.RGB_565);
    }

    private int getRGB(short sh) {
        //31 -> 5
        //63 -> 6
        int r = (sh & 0xF8) >>> 3;
        int b = (sh & 0x1F00) >>> 8;
        int g1 = (sh & 0x7) << 3;
        int g2 = (sh & 0xE000) >>> 13;
        //这种当五位去算，颜色值差异不大
        /*int g1 = (sh & 0x7) << 2;
        int g2 = (sh & 0xE000) >>> 14;*/
        //高位放在高位不行
        /*int g1 = (sh & 0x7);
        int g2 = (sh & 0xE000) >>> 10;*/
        return Color.rgb(getRGBOne(r, false)
                , getRGBOne(g1 + g2, true)
                , getRGBOne(b, false));
    }

    private int getRGBOne(int i, boolean long_) {
        if (long_) return (int) (i * 255.0f / 63);
        else return (int) (i * 255.0f / 31);
    }
}
